package com.china08.yxyapi.api.manage.tec.teaching.lecture.prepare;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.china08.yxyapi.api.YxyApiBaseController;
import com.china08.yxyapi.entity.db.res.YxyResResource;
import com.china08.yxyapi.entity.es.ElasticYxyYxyQuesResource;
import com.china08.yxyapi.entity.mg.lecture.YxyLecturePack;
import com.china08.yxyapi.entity.mg.lecture.YxyLecturePack.Res;
import com.china08.yxyapi.entity.mg.lecture.YxyLectureRes;
import com.china08.yxyapi.entity.mg.lecture.YxyLectureRes.Knows;
import com.china08.yxyapi.entity.mg.res.AllTemplate;
import com.china08.yxyapi.entity.mg.res.AllTemplate.Answer;
import com.china08.yxyapi.entity.mg.res.AllTemplate.Branch;
import com.china08.yxyapi.model.YxyApiReqModel;
import com.china08.yxyapi.model.YxyApiRespModel;
import com.china08.yxyapi.repository.db.YxyResResourceRepository;
import com.china08.yxyapi.repository.mg.lecture.YxyLecturePackRepository;
import com.china08.yxyapi.repository.mg.lecture.YxyLectureResRepository;
import com.china08.yxyapi.service.manage.tec.teaching.homework.ElasticQuesService;
import com.china08.yxyapi.util.DESUtil;
import com.china08.yxyapi.util.DateUtils;
import com.china08.yxyapi.util.ObjectToMap;
import com.china08.yxyapi.util.RedisDownUtil;
import com.china08.yxyapi.util.YxyResUtil;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import net.lingala.zip4j.core.ZipFile;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.Zip4jConstants;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;

/**
 * 教师课前准备-下载授课包
 * 
 */
@Api
@CrossOrigin
@RestController
public class LecturePrePackDownLoadController extends YxyApiBaseController {

    public static Logger log = Logger.getLogger(LecturePrePackDownLoadController.class);

    @Autowired
    YxyLecturePackRepository lecturePackRepository;

    @Autowired
    YxyResUtil YxyResUtil;

    @Autowired
    ElasticQuesService elasticQuesService;

    @Autowired
    YxyLectureResRepository yxyLectureResRepository;

    @Autowired
    YxyResResourceRepository yxyResResourceRepository;

    @Value("${yw.esbag.pack.tmp.dir}")
    private String userHome;

    @Value("${weike.storage.upload.video}")
    private String yxyResUpload;

    @Autowired
    private RedisDownUtil redisDownUtil;

    @Value("${salt.esbag}")
    private String saltEsbag;

    @ApiOperation(value = "下载授课包")
    @RequestMapping(value = "/api_yw/manage/tec/teaching/lecture/prepare/download", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public RespModel process(HttpServletRequest request, HttpServletResponse response, RespModel respModel,
            @RequestBody ReqModel reqModel) throws IOException {

        // 获取用户基本信息
        String userId = getProfile(request, response).getId();
        String schoolId = getProfile(request, response).getSchoolId();

        // 权限参数验证
        Assert.notNull(StringUtils.defaultIfBlank(userId, null), "用户id必须");
        Assert.notNull(StringUtils.defaultIfBlank(schoolId, null), "学校id必须");

        // 授课包验证
        YxyLecturePack lecturePack = lecturePackRepository.findById(reqModel.packId);
        if (lecturePack == null) {
            Assert.isTrue(false, "授课包不存在");
        }
        if (lecturePack.getResources() == null || lecturePack.getResources().size() == 0) {
            Assert.isTrue(false, "授课包下不存在资源，不能进行下载");
        }

        String dataStr = DateUtils.formatDate2(new Date());

        // 文件状态存放位置
        String filePath = getUserHome() + "/" + ".YxYun-YxYunApiTplForYw" + "/" + dataStr + "/download/pack/" + userId
                + "/" + lecturePack.getId();

        // 打包的zip包名称
        String zipName = "pack";
        respModel.zipName = zipName;

        // 下载的文件存放路径
        String packFilePath = filePath + "/" + "pack";
        File packFile = new File(packFilePath);
        if (!packFile.exists()) {
            packFile.mkdirs();
        } else {
            // 上一次下载时间
            Long dateTime1 = redisDownUtil.get(userId + "_" + lecturePack.getId());
            Long dateTime2 = new Date().getTime();
            if (dateTime1 == null || dateTime2 - dateTime1 > 5000) {
                // 删除文件夹
                try {
                    System.gc();
                    Thread.sleep(3000);
                    deleteDir(new File(filePath));
                } catch (Exception e) {
                } finally {
                    try {
                        deleteDir(new File(filePath));
                    } catch (Exception e2) {
                    }
                }
                // 重新生成-下载的文件存放路径
                if (!packFile.exists()) {
                    packFile.mkdirs();
                }
            } else {
                return respModel;
            }
        }

        // zip存放的路径
        String zipFilePath = filePath + "/" + "zip";
        respModel.zipFilePath = zipFilePath;
        File file = new File(zipFilePath);
        if (!file.exists()) {
            file.mkdirs();
        }

        // zip 存放的文件
        String zipfileUrl = zipFilePath + "/" + zipName + ".zip";

        // 备授课请求下载位置
        String downFilePath = filePath + "/" + "down";
        File downFile = new File(downFilePath);
        if (!downFile.exists()) {
            downFile.mkdirs();
        }

        // 存放题组的路径
        String quesPath = packFilePath + "/question";
        File quesPathFile = new File(quesPath);
        if (!quesPathFile.exists()) {
            quesPathFile.mkdirs();
        }

        // 文件下载的状态存储(文件名字存储方式) X1_X2_X3_X4;
        // X1: 状态(0-失败, 1-下载中, 2下载完成, 3打包中, 4打包完成)
        // X2: 下载大小,
        // X3: 打包文件大小
        // X4: 文件总大小
        // ## 生成文件夹
        String statusFilePath = filePath + "/" + "status";
        File statusFile = new File(statusFilePath);
        if (!statusFile.exists()) {
            statusFile.mkdirs();
        }
        // ## statusName
        String statusName = "%s_%s_%s_%s";
        // ## status 状态(0-失败, 1-下载中, 2下载完成, 3打包中, 4打包完成)
        int status = 1;
        // ## 获取需要下载文件总大小
        Long number1 = 0l;
        for (YxyLecturePack.Res res : lecturePack.getResources()) {
            Integer usesTeaching = res.getUsesTeaching();
            Integer usesTest = res.getUsesTest();
            if ((usesTeaching != null && usesTeaching == 1) || (usesTest != null && usesTest == 1)) {
                HttpURLConnection connection = null;
                URL url = new URL(YxyResUtil.getDownloadUrl(res.getResourceId()));
                try {
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setConnectTimeout(3000); // 连接url超时时间(毫秒)
                    connection.setReadTimeout(3000); // 读取数据超时时间(毫秒)
                    connection.setRequestProperty("Accept-Encoding", "identity");
                    number1 = number1 + connection.getContentLength();
                } catch (Exception e) {
                } finally {
                    // 关闭连接
                    if (connection != null) {
                        try {
                            connection.disconnect();
                            connection = null;
                        } catch (Exception e) {
                        }
                    }
                }
            }
        }
        Long number = number1;
        // ## 生成文件
        File statusfile = new File(statusFilePath + "/" + String.format(statusName, status, 0, 0, number));
        if (!statusfile.exists()) {
            statusfile.createNewFile();
            log.info("备课包：" + lecturePack.getPackName() + "，status：" + String.format(statusName, status, 0, 0, number));
        }
        // 监控下载使用
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                // 记录下载时间
                try {
                    while (true) {
                        String[] split = statusFile.listFiles()[0].getName().split("_");
                        int status = Integer.parseInt(split[0]);
                        if (status == 0 || status == 4) { return; }
                        // 记录下载时间
                        redisDownUtil.set(userId + "_" + lecturePack.getId());
                        log.info("授课包正在下载..." + "（" + userId + "!@!" + lecturePack.getId() + "）");
                        Thread.sleep(3000);
                    }
                } catch (InterruptedException e) {
                }
            }
        });
        thread1.start();
        // 开启线程，启动备课包下载
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 资源数量
                int resTotal = 0;
                for (Res res : lecturePack.getResources()) {
                    Integer usesTeaching = res.getUsesTeaching();
                    Integer usesTest = res.getUsesTest();
                    if ((usesTeaching != null && usesTeaching == 1) || (usesTest != null && usesTest == 1)) {
                        resTotal++;
                    }
                }
                // 下载资源成功的资源数量
                int resDownTotal = 0;
                // ## 下载大小
                Long downNumber = 0l;
                // ## 打包大小
                Long zipNumber = 0l;
                // 下载状态log
                log.info("备课包：" + lecturePack.getPackName() + "，(total：" + resTotal + ")开始下载...");
                for (YxyLecturePack.Res res : lecturePack.getResources()) {
                    // 只下载 教学 AND 测试
                    Integer usesTeaching = res.getUsesTeaching();
                    Integer usesTest = res.getUsesTest();
                    if (!((usesTeaching != null && usesTeaching == 1) || (usesTest != null && usesTest == 1))) {
                        continue;
                    }
                    // 为了好拆分, 题组/文件 下载方式完全分开
                    // ## 资源 OR 微课
                    if (res.getCourseType() == 1) {
                        log.info("备课包：" + lecturePack.getPackName() + "， 文件：" + res.getResourceName() + "，("
                                + (resDownTotal + 1) + "/" + resTotal + ")开始下载...");
                        // 下载时间统计
                        long start = System.currentTimeMillis();
                        // 下载的文件 resourceUrl
                        String resourceUrl = YxyResUtil.getDownloadUrl(res.getResourceId());
                        HttpURLConnection connection = null;
                        File resfile = null;
                        try {
                            // 正式环境
                            YxyResResource yxyResResource = yxyResResourceRepository.findById(res.getResourceId());
                            if (yxyResResource != null) {
                                String location = yxyResResource.getLocation();
                                if (location != null) {
                                    resfile = new File(yxyResUpload + location);
                                    log.info("备课包：" + lecturePack.getPackName() + "， 下载路径：" + yxyResUpload + location);
                                } else {
                                    log.info("备课包：" + lecturePack.getPackName()
                                            + "， 没有文件下载路径(yxyResResource.getLocation())");
                                }
                            } else {
                                log.info("备课包：" + lecturePack.getPackName() + "， 没有找到资源(yxyResResource)");
                            }
                            // 测试环境
                            boolean isResExist = (resfile != null && resfile.exists());
                            if (!isResExist) {
                                log.info("备课包：" + lecturePack.getPackName() + "， 下载方式 ：文件系统没有文件，启用HTTP方式下载");
                                URL url = new URL(resourceUrl);
                                // 远程连接
                                connection = (HttpURLConnection) url.openConnection();
                                connection.setConnectTimeout(3000); // 连接url超时时间(毫秒)
                                connection.setReadTimeout(1000 * 60 * 60); // 读取数据超时时间(毫秒)
                                connection.setRequestProperty("User-Agent",
                                        "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); // 防止屏蔽程序抓取而返回403错误
                                connection.setRequestProperty("Accept-Encoding", "identity");
                            } else {
                                log.info("备课包：" + lecturePack.getPackName() + "， 下载方式 ：通过文件系统进行下载");
                            }
                            int code = isResExist ? 200 : connection.getResponseCode();
                            // 连接成功
                            if (code == 200) {
                                // 获得二进制输入流
                                InputStream inputStream = null;
                                // 缓存区，二进制输入流
                                BufferedInputStream bufferedInputStream = null;
                                // 二进制输出流
                                FileOutputStream fileOutputStream = null;
                                // 缓存区二进制输出流
                                BufferedOutputStream bufferedOutputStream = null;

                                try {
                                    inputStream = isResExist ? new FileInputStream(resfile)
                                            : connection.getInputStream();
                                    bufferedInputStream = new BufferedInputStream(inputStream, 1024);
                                    // 存放本次文件的路径
                                    String resourceName = res.getResourceName().trim().replaceAll(" ", "")
                                            .replaceAll(" ", "");
                                    File file = new File(packFilePath + "/" + resourceName);
                                    if (!file.exists()) {
                                        file.createNewFile();
                                    }
                                    fileOutputStream = new FileOutputStream(file);
                                    bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                                    // 读取写入
                                    int length;
                                    // 每次读取字节数
                                    byte[] b = new byte[1024];
                                    while ((length = bufferedInputStream.read(b, 0, b.length)) != -1) {
                                        bufferedOutputStream.write(b, 0, length);
                                    }
                                    // 下载时间统计
                                    long end = System.currentTimeMillis();
                                    log.info("备课包：" + lecturePack.getPackName() + "， 文件：" + res.getResourceName() + "，("
                                            + (resDownTotal + 1) + "/" + resTotal + ")下载完成(" + (end - start) + ")");
                                    // 下载大小叠加
                                    downNumber = downNumber + Long.valueOf(
                                            isResExist ? inputStream.available() : connection.getContentLength());
                                    // 更新状态
                                    statusFile.listFiles()[0].renameTo(new File(statusFilePath + "/"
                                            + String.format(statusName, 1, downNumber, zipNumber, number)));
                                    // 下载完成资源数量
                                    resDownTotal++;
                                } catch (Exception e) {
                                    // 下载时间统计
                                    long end = System.currentTimeMillis();
                                    log.info("备课包：" + lecturePack.getPackName() + "， 文件：" + res.getResourceName() + "，("
                                            + (resDownTotal + 1) + "/" + resTotal + ")下载失败(" + (end - start) + ")");
                                    // 内部捕获异常抛出，给你外部 catch 处理
                                    log.info("Error：" + e.getMessage());
                                    log.info("Error", e);
                                    throw e;
                                } finally {
                                    // 关闭流 缓存区二进制输出流
                                    if (bufferedOutputStream != null) {
                                        try {
                                            bufferedOutputStream.close();
                                            bufferedOutputStream = null;
                                        } catch (Exception e) {
                                        }
                                    }
                                    // 关闭流 二进制输出流
                                    if (fileOutputStream != null) {
                                        try {
                                            fileOutputStream.close();
                                            fileOutputStream = null;
                                        } catch (Exception e) {
                                        }
                                    }
                                    // 关闭流 缓存区，二进制输入流
                                    if (bufferedInputStream != null) {
                                        try {
                                            bufferedInputStream.close();
                                            bufferedInputStream = null;
                                        } catch (Exception e) {
                                        }
                                    }
                                    // 关闭流 二进制输入流
                                    if (inputStream != null) {
                                        try {
                                            inputStream.close();
                                            inputStream = null;
                                        } catch (Exception e) {
                                        }
                                    }
                                }
                            } else {
                                log.info("备课包：" + lecturePack.getPackName() + "， 文件：" + res.getResourceName()
                                        + "，和资源库连接失败，(" + (resDownTotal + 1) + "/" + resTotal + ")下载连接失败(code:" + code
                                        + ")");
                            }
                        } catch (Exception e) {
                            // 更新状态 (失败)
                            statusFile.listFiles()[0].renameTo(new File(statusFilePath + "/"
                                    + String.format(statusName, 0, downNumber, zipNumber, number)));
                            // 异常日志打印
                            log.info("Error：" + e.getMessage());
                            log.info("Error", e);
                        } finally {
                            // 关闭连接
                            if (connection != null) {
                                try {
                                    connection.disconnect();
                                    connection = null;
                                } catch (Exception e) {
                                }
                            }
                        }
                    }

                    System.gc();

                    // ## 题组下载
                    if (res.getCourseType() == 0) {
                        // 记录本次题组是否下载完成
                        boolean flag = false;
                        // 下载时间统计
                        long start = System.currentTimeMillis();
                        // 日志
                        log.info("备课包：" + lecturePack.getPackName() + "， 题组：" + res.getResourceName() + "，("
                                + (resDownTotal + 1) + "/" + resTotal + ")开始下载...");
                        // 文件中写入字符数据的字符流输出流对象
                        FileOutputStream fileStream = null;
                        OutputStreamWriter writer = null;
                        try {
                            // 存放题组的文件
                            String quesResPath = quesPath + "/" + res.getResourceId();
                            // 文件中写入字符数据的字符流输出流对象
                            // 文件字符流
                            File quesResfile = new File(quesResPath);
                            if (!quesResfile.exists()) {
                                quesResfile.createNewFile();
                            }
                            fileStream = new FileOutputStream(quesResfile);
                            writer = new OutputStreamWriter(fileStream, "UTF-8");
                            // 获取题组资源
                            YxyLectureRes yxyLectureRes = yxyLectureResRepository.findByResourceId(res.getResourceId());
                            // ## 获取试题
                            List<String> quesIds = yxyLectureRes.getQuesIds();
                            List<ElasticYxyYxyQuesResource> elasticYxyYxyQuesResources = elasticQuesService
                                    .findByQuesIdIn(quesIds);
                            // 按照试题： 单选题、多选题，填空题、简答题
                            List<ElasticYxyYxyQuesResource> eList = new ArrayList<ElasticYxyYxyQuesResource>();
                            if (elasticYxyYxyQuesResources != null && elasticYxyYxyQuesResources.size() > 0) {
                                // 单选题
                                for (ElasticYxyYxyQuesResource es : elasticYxyYxyQuesResources) {
                                    if (es.getQuestionType().equals("1")) {
                                        eList.add(es);
                                    }
                                }
                                // 多选题
                                for (ElasticYxyYxyQuesResource es : elasticYxyYxyQuesResources) {
                                    if (es.getQuestionType().equals("8")) {
                                        eList.add(es);
                                    }
                                }
                                // 填空题
                                for (ElasticYxyYxyQuesResource es : elasticYxyYxyQuesResources) {
                                    if (es.getQuestionType().equals("2")) {
                                        eList.add(es);
                                    }
                                }
                                // 简答题
                                for (ElasticYxyYxyQuesResource es : elasticYxyYxyQuesResources) {
                                    if (!es.getQuestionType().equals("1") && !es.getQuestionType().equals("8")
                                            && !es.getQuestionType().equals("2")) {
                                        eList.add(es);
                                    }
                                }
                            }
                            // 存放试题List
                            List<Question> questions = new ArrayList<>();
                            // ## 遍历试题
                            for (ElasticYxyYxyQuesResource eQues : eList) {
                                // 试题Id
                                String id = eQues.getId();
                                // 试题内容
                                AllTemplate quesBodyTemplate = (AllTemplate) eQues.getQuesBody();
                                // 试题难度值
                                String difficultyLevel = eQues.getDifficultyLevel();
                                // 试题关联知识点
                                Map<String, List<Knows>> quesKnows = yxyLectureRes.getQuesKnows();
                                List<Integer> knowledgeIds = new ArrayList<>();
                                List<String> knowledgeTexts = new ArrayList<>();
                                if (quesKnows != null) {
                                    List<Knows> list = quesKnows.get(id);
                                    if (list != null && list.size() > 0) {
                                        for (int i = 0; i < list.size(); i++) {
                                            Knows knows = list.get(i);
                                            if (knows == null) { return; }
                                            knowledgeIds.add(Integer.parseInt(knows.know_id));
                                            knowledgeTexts.add(knows.know_name);
                                        }
                                    }
                                }
                                // 试题类型 1单选 2填空 8多选 其他解答
                                String questionType = eQues.getQuestionType();
                                // 题干
                                String body = srcUrlchangeBase64(quesBodyTemplate.sub.stem.body);
                                if (body != null && body.contains("quizPutTag")) {
                                    // 开始匹配
                                    Matcher m1 = Pattern.compile("<div class=\"quizPutTag\">(.*?)<\\/div>")
                                            .matcher(body);
                                    while (m1.find()) {
                                        // 获取到匹配的标签中的内容
                                        String str = "<div class=\"quizPutTag\">" + m1.group(1) + "</div>";
                                        body = body.replace(str, "<div class=\"quizPutTag\">______</div>");
                                    }
                                    // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                    // 开始匹配
                                    Matcher m2 = Pattern.compile("<div class=\"sanwser\">(.*?)<\\/div>").matcher(body);
                                    while (m2.find()) {
                                        // 获取到匹配的标签中的内容
                                        String str = "<div class=\"sanwser\">" + m2.group(1) + "</div>";
                                        body = body.replace(str, "");
                                    }
                                }
                                // 选项
                                List<Branch> branch = new ArrayList<>();// 正确选项
                                if (quesBodyTemplate.sub.branch != null && quesBodyTemplate.sub.branch.size() > 0) {
                                    for (Branch branch1 : quesBodyTemplate.sub.branch) {
                                        branch1.body = srcUrlchangeBase64(branch1.body);
                                        branch.add(branch1);
                                    }
                                }
                                // 答案
                                List<Answer> answer = new ArrayList<AllTemplate.Answer>(); // 正确答案
                                if (quesBodyTemplate.sub.answer != null && quesBodyTemplate.sub.answer.size() > 0) {
                                    for (Answer answer1 : quesBodyTemplate.sub.answer) {
                                        answer1.body = srcUrlchangeBase64(answer1.body);
                                        answer.add(answer1);
                                    }
                                }
                                // 分析
                                String analysis = srcUrlchangeBase64(quesBodyTemplate.sub.analysis.body);
                                // 点评
                                String comment = srcUrlchangeBase64(quesBodyTemplate.sub.comment.body);
                                // 解析
                                String solution = srcUrlchangeBase64(quesBodyTemplate.sub.solution.body);
                                // list add
                                Question question = new Question();
                                question.id = id;
                                question.body = body;
                                question.branch = branch;
                                question.answer = answer;
                                question.analysis = analysis;
                                question.comment = comment;
                                question.solution = solution;
                                question.difficultyLevel = difficultyLevel;
                                question.knowledgeIds = knowledgeIds;
                                question.knowledgeTexts = knowledgeTexts;
                                question.questionType = questionType;
                                questions.add(question);
                            }
                            // 获取需要写入数据
                            QuesGroup quesGroup = new QuesGroup();
                            quesGroup.resId = yxyLectureRes.getResourceId();
                            quesGroup.resName = yxyLectureRes.getResName();
                            quesGroup.questions = questions;
                            // 对象转Json
                            String JsonQuesGroup = JSONObject.toJSONString(ObjectToMap.convertObjToMap(quesGroup));
                            // 对象Json 写入 fw
                            writer.write(JsonQuesGroup);
                            // 进行刷新，将字符写到目的地中
                            writer.flush();
                            // 下载大小叠加
                            downNumber = downNumber + Long.valueOf(JsonQuesGroup.getBytes().length);
                            // 更新状态
                            statusFile.listFiles()[0].renameTo(new File(statusFilePath + "/"
                                    + String.format(statusName, 1, downNumber, zipNumber, number)));
                            // 本次题组下载完成标识
                            flag = true;
                            // 下载完成资源数量
                            resDownTotal++;
                        } catch (Exception e) {
                            // 更新状态 (失败)
                            statusFile.listFiles()[0].renameTo(new File(statusFilePath + "/"
                                    + String.format(statusName, 0, downNumber, zipNumber, number)));
                            // 异常日志打印
                            log.info("Error：" + e.getMessage());
                            log.info("Error", e);
                        } finally {
                            // 下载时间统计
                            long end = System.currentTimeMillis();
                            // 本次下载是否成功
                            if (flag) {
                                // 日志输出
                                log.info("备课包：" + lecturePack.getPackName() + "， 题组：" + res.getResourceName() + "，("
                                        + (resDownTotal) + "/" + resTotal + ")下载完成(" + (end - start) + ")");
                            } else {
                                // 日志输出
                                log.info("备课包：" + lecturePack.getPackName() + "， 题组：" + res.getResourceName() + "，("
                                        + (resDownTotal + 1) + "/" + resTotal + ")下载失败(" + (end - start) + ")");
                            }
                            // 关闭流
                            if (writer != null) {
                                try {
                                    writer.close();
                                    writer = null;
                                } catch (IOException e) {
                                }
                            }
                            if (fileStream != null) {
                                try {
                                    fileStream.close();
                                    fileStream = null;
                                } catch (IOException e) {
                                }
                            }
                        }
                    }
                }

                System.gc();

                // 判断是否下载完成
                boolean flag = false;
                try {
                    if (resDownTotal == resTotal) {
                        flag = true;
                        // 下载状态log
                        log.info("备课包：" + lecturePack.getPackName() + "，(" + resDownTotal + "/" + resTotal + ")下载完成");
                        // 更新状态
                        statusFile.listFiles()[0].renameTo(new File(
                                statusFilePath + "/" + String.format(statusName, 2, downNumber, zipNumber, number)));
                        log.info("备课包：" + lecturePack.getPackName() + "，status："
                                + String.format(statusName, 2, downNumber, zipNumber, number));
                    } else {
                        flag = false;
                        // 下载状态log
                        log.info("备课包：" + lecturePack.getPackName() + "，(" + resDownTotal + "/" + resTotal + ")下载失败");
                        // 更新状态
                        statusFile.listFiles()[0].renameTo(new File(
                                statusFilePath + "/" + String.format(statusName, 0, downNumber, zipNumber, number)));
                        log.info("备课包：" + lecturePack.getPackName() + "，status："
                                + String.format(statusName, 0, downNumber, zipNumber, number));
                        return;
                    }
                } catch (Exception e2) {
                    // 更新状态 (失败)
                    statusFile.listFiles()[0].renameTo(new File(
                            statusFilePath + "/" + String.format(statusName, 0, downNumber, zipNumber, number)));
                    // 异常日志打印
                    log.info("Error：" + e2.getMessage());
                    log.info("Error", e2);
                }

                // *授课包基本信息生成*，写入文档
                if (flag) {
                    // 修改需要生成的数据
                    for (YxyLecturePack.Res res : lecturePack.getResources()) {
                        // 题组下载
                        if (res.getCourseType() == 0) {
                            res.setResourceUrl(userId + '/' + lecturePack.getId() + "/" + "pack" + "/" + "question"
                                    + "/" + res.getResourceId());
                        } // 资源下载
                        else if (res.getCourseType() == 1) {
                            String resourceName = res.getResourceName().trim().replaceAll(" ", "").replaceAll(" ", "");
                            res.setResourceUrl(userId + '/' + lecturePack.getId() + "/" + "pack" + "/" + resourceName);
                            // 没有后缀，增加后缀
                            if (!res.getResourceName().contains(".")) {
                                YxyResResource yxyResResource = yxyResResourceRepository.findById(res.getResourceId());
                                if (yxyResResource != null) {
                                    res.setResourceName(
                                            res.getResourceName().concat(".").concat(yxyResResource.getExtension()));
                                }
                            }
                        }
                    }
                    // 文件字符流
                    FileOutputStream fileStream = null;
                    OutputStreamWriter writer = null;
                    try {
                        // 文件字符流
                        File lecturePackDBfile = new File(packFilePath + "/" + "LecturePack.db");
                        if (!lecturePackDBfile.exists()) {
                            lecturePackDBfile.createNewFile();
                        }
                        fileStream = new FileOutputStream(lecturePackDBfile);
                        writer = new OutputStreamWriter(fileStream, "UTF-8");
                        // 对象转Json
                        String JsonLecturePack = JSONObject.toJSONString(ObjectToMap.convertObjToMap(lecturePack));
                        // 对象Json 写入 fw
                        writer.write(JsonLecturePack);
                        // 进行刷新，将字符写到目的地中
                        writer.flush();
                    } catch (Exception e) {
                        // 更新状态 (失败)
                        statusFile.listFiles()[0].renameTo(new File(
                                statusFilePath + "/" + String.format(statusName, 0, downNumber, zipNumber, number)));
                        // 异常日志打印
                        log.info("Error：" + e.getMessage());
                        log.info("Error", e);
                    } finally {
                        // 关闭流
                        if (writer != null) {
                            try {
                                writer.close();
                                writer = null;
                            } catch (IOException e1) {
                            }
                        }
                        if (fileStream != null) {
                            try {
                                fileStream.close();
                                fileStream = null;
                            } catch (IOException e1) {
                            }
                        }
                    }
                }

                System.gc();

                // 学生信息写入备课包
                if (flag) {
                    // 文件字符流
                    FileOutputStream fileStream = null;
                    OutputStreamWriter writer = null;
                    try {
                        // 文件字符流
                        File studentDBfile = new File(packFilePath + "/" + "Student.db");
                        if (!studentDBfile.exists()) {
                            studentDBfile.createNewFile();
                        }
                        fileStream = new FileOutputStream(studentDBfile);
                        writer = new OutputStreamWriter(fileStream, "UTF-8");
                        //
                        List<Map<String, Object>> maps = new ArrayList<>();
                        reqModel.students.forEach(stu -> {
                            Map<String, Object> map = new HashMap<String, Object>();
                            map.put("studentId", stu.studentId);
                            map.put("studentName", stu.studentName);
                            map.put("avatar", stu.avatar);
                            map.put("avatarUrl", stu.avatarUrl);
                            maps.add(map);
                        });
                        // 对象转Json
                        String JsonStudents = JSONArray.toJSONString(maps);
                        // 对象Json 写入 fw
                        writer.write(JsonStudents);
                        // 进行刷新，将字符写到目的地中
                        writer.flush();
                    } catch (Exception e) {
                        // 更新状态 (失败)
                        statusFile.listFiles()[0].renameTo(new File(
                                statusFilePath + "/" + String.format(statusName, 0, downNumber, zipNumber, number)));
                        // 异常日志打印
                        log.info("Error：" + e.getMessage());
                        log.info("Error", e);
                    } finally {
                        // 关闭流
                        if (writer != null) {
                            try {
                                writer.close();
                                writer = null;
                            } catch (IOException e1) {
                            }
                        }
                        if (fileStream != null) {
                            try {
                                fileStream.close();
                                fileStream = null;
                            } catch (IOException e1) {
                            }
                        }
                    }
                }

                System.gc();

                // 如要打包文件总数
                int total = resTotal;
                // 打入压缩包文件数量
                int zipTotal = 0;
                // 如果备课包资源下载完成，把下载的资源打包(zip)
                if (flag) {
                    // 更新状态
                    statusFile.listFiles()[0].renameTo(new File(
                            statusFilePath + "/" + String.format(statusName, 3, downNumber, zipNumber, number)));
                    // 日志
                    log.info("备课包：" + lecturePack.getPackName() + "，(数量：" + total + ")打包开始...");
                    try {
                        // DES 加密
                        String password = DESUtil.encryption(userId + ":" + saltEsbag, saltEsbag);
                        log.info("备课包：打包加密 key [ " + saltEsbag + " ]");
                        log.info("备课包：打包加密 str [ " + userId + ":" + saltEsbag + " ]");
                        log.info("备课包：打包密码 [ " + password + " ]");
                        // 初始化各类参数
                        ZipParameters parameters = new ZipParameters();
                        // 设置压缩模式
                        parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
                        parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
                        parameters.setEncryptFiles(true);
                        parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
                        parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
                        parameters.setPassword(password);
                        // 压缩指定文件
                        ZipFile zipFile = new ZipFile(zipfileUrl);
                        zipFile.addFolder(packFile, parameters);
                        // 修改文件后缀
                        copyFile(zipFilePath + "/" + zipName + ".zip", zipFilePath + "/" + zipName + ".esbagpack");
                        // 打包完成
                        log.info("备课包：" + lecturePack.getPackName() + "，(" + zipTotal + "/" + total + ")打包完成");
                        // 文件复制
                        copyFile(zipFilePath + "/" + zipName + ".esbagpack",
                                downFilePath + "/" + lecturePack.getPackName() + ".esbagpack");
                        // 更新状态
                        statusFile.listFiles()[0].renameTo(new File(
                                statusFilePath + "/" + String.format(statusName, 4, downNumber, zipNumber, number)));
                        log.info("备课包：" + lecturePack.getPackName() + "，status："
                                + String.format(statusName, 4, downNumber, zipNumber, number));
                    } catch (Exception e) {
                        // 异常日志打印
                        log.info("Error：" + e.getMessage());
                        log.info("Error", e);
                        log.info("备课包：" + lecturePack.getPackName() + "，(" + zipTotal + "/" + total + ")打包失败");
                        // 更新状态 (失败)
                        statusFile.listFiles()[0].renameTo(new File(
                                statusFilePath + "/" + String.format(statusName, 0, downNumber, zipNumber, number)));
                        log.info("备课包：" + lecturePack.getPackName() + "，status："
                                + String.format(statusName, 0, downNumber, zipNumber, number));
                    }
                }
            }
        });
        thread.start();

        respModel.dataStr = dataStr;
        return respModel;
    }

    /** 请求数据 */
    protected static class ReqModel extends YxyApiReqModel {
        public String packId; // 授课资源包Id
        public List<Student> students;
    }

    protected static class Student {
        public String studentId;
        public String studentName;
        public String avatar;
        public String avatarUrl;
    }

    /** 响应 */
    protected static class RespModel extends YxyApiRespModel {
        public String zipName; // zip 包下载名称
        public String zipFilePath; // zip包存在本地服务器路径
        public String dataStr; // 下载时间 （yyyy-MM-dd）
    }

    /** 题组输出信息 **/
    protected static class QuesGroup {
        public String resId; // Id
        public String resName; // 分组名称
        public List<Question> questions; // 试题列表
    }

    /** 试题信息输出 **/
    protected static class Question {
        public String id; // 试题Id
        public String difficultyLevel; // 试题难度值
        public List<Integer> knowledgeIds; // 试题关联知识点Id
        public List<String> knowledgeTexts; // 试题关联知识点名称
        public String questionType; // 试题类型 1单选 2填空 8多选 其他解答
        public String body; // 题干
        public List<Branch> branch; // 选项
        public List<Answer> answer; // 答案
        public String analysis; // 分析
        public String comment; // 点评
        public String solution; // 解析
    }

    /** 获取字符串中的src **/
    private List<String> getImgSrcList(String content) {
        List<String> list = new ArrayList<String>();
        // 开始匹配content中的<img />标签
        Pattern p_img = Pattern.compile("<(img|IMG)(.*?)(/>|></img>|>)");
        Matcher m_img = p_img.matcher(content);
        boolean result_img = m_img.find();
        if (result_img) {
            while (result_img) {
                // 获取到匹配的<img />标签中的内容
                String str_img = m_img.group(2);
                // 开始匹配<img />标签中的src
                Pattern p_src = Pattern.compile("(src|SRC)=(\"|\')(.*?)(\"|\')");
                Matcher m_src = p_src.matcher(str_img);
                if (m_src.find()) {
                    String str_src = m_src.group(3);
                    list.add(str_src);
                }
                // 匹配content中是否存在下一个<img />标签，有则继续以上步骤匹配<img />标签中的src
                result_img = m_img.find();
            }
        }
        return list;
    }

    /**
     * 匹配字符串中的src, 并把src路径转化为base64 ( 暂时全部转化为：data:image/png;base64, )
     * 
     * @throws IOException
     **/
    private String srcUrlchangeBase64(String content) throws IOException {
        if (content == null || content.trim().length() == 0) { return content; }
        // 获取 url 集合
        List<String> urls = this.getImgSrcList(content);
        if (urls != null && urls.size() > 0) {
            for (String srcUrl : urls) {
                byte[] data = null;
                try {
                    data = Jsoup.connect(srcUrl).ignoreContentType(true).execute().bodyAsBytes();
                    String srcBase64 = "data:image/png;base64,".concat(new Base64().encodeToString(data));
                    content = content.replace(srcUrl, srcBase64);
                } catch (Exception e) {
                    if (e instanceof UnknownHostException) {
                        log.info("srcUrlchangeBase64java error: .net.UnknownHostException: " + srcUrl);
                    } else {
                        log.info("srcUrlchangeBase64java error: " + e);
                    }
                }
            }
        }
        return content;
    }

    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     * 
     * @param dir
     *            将要删除的文件目录
     * @return boolean Returns "true" if all deletions were successful. If a
     *         deletion fails, the method stops attempting to delete and returns
     *         "false".
     */
    private void deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            // 递归删除目录中的子目录下
            for (int i = 0; i < children.length; i++) {
                deleteDir(new File(dir + "/" + children[i]));
            }
            boolean result = dir.delete();
            if (!result) {
                System.gc();
                dir.delete();
            }
        } else {
            boolean result = dir.delete();
            if (!result) {
                System.gc();
                dir.delete();
            }
        }
    }

    /**
     * 复制单个文件
     * 
     * @param oldPath
     * @param newPath
     */
    public void copyFile(String oldPath, String newPath) {

        // 获得二进制输入流
        InputStream inputStream = null;
        // 缓存区，二进制输入流
        BufferedInputStream bufferedInputStream = null;
        // 二进制输出流
        FileOutputStream fileOutputStream = null;
        // 缓存区二进制输出流
        BufferedOutputStream bufferedOutputStream = null;

        try {
            inputStream = new FileInputStream(oldPath);
            bufferedInputStream = new BufferedInputStream(inputStream, 1024);
            // 存放本次文件的路径
            File file = new File(newPath);
            if (!file.exists()) {
                file.createNewFile();
            }
            fileOutputStream = new FileOutputStream(file);
            bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            // 读取写入
            int length;
            // 每次读取字节数
            byte[] b = new byte[1024];
            while ((length = bufferedInputStream.read(b, 0, b.length)) != -1) {
                bufferedOutputStream.write(b, 0, length);
            }
            log.info("copyFile copy ok ...");
        } catch (Exception e) {
            log.info("copyFile Error：" + e.getMessage());
            log.info("copyFile Error", e);
        } finally {
            // 关闭流 缓存区二进制输出流
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close();
                    bufferedOutputStream = null;
                } catch (Exception e) {
                }
            }
            // 关闭流 二进制输出流
            if (fileOutputStream != null) {
                try {
                    fileOutputStream.close();
                    fileOutputStream = null;
                } catch (Exception e) {
                }
            }
            // 关闭流 缓存区，二进制输入流
            if (bufferedInputStream != null) {
                try {
                    bufferedInputStream.close();
                    bufferedInputStream = null;
                } catch (Exception e) {
                }
            }
            // 关闭流 二进制输入流
            if (inputStream != null) {
                try {
                    inputStream.close();
                    inputStream = null;
                } catch (Exception e) {
                }
            }
        }
    }

    public String getUserHome() {
        return userHome;
    }

    public void setUserHome(String userHome) {
        this.userHome = userHome;
    }

    // \home\YunXiao\YxyTmpShareDir\YxyESBagPackTmpDir\.YxYun-YxYunElectronicSchoolBagApiYw\2017-08-11\download\pack\ff8080815d30e4f3015d346b02bf0011\598c0f63d433ed0d9651c31f\pack
    // /home/YunXiao/YxyTmpShareDir/YxyESBagPackTmpDir/.YxYun-YxYunElectronicSchoolBagApiYw/2017-08-11/download/pack/ff8080815d30e4f3015d346b02bf0011/598c0f63d433ed0d9651c31f/zip/pack.zip

    // // 初始化各类参数
    // ZipParameters parameters = new ZipParameters();
    // // 设置压缩模式
    // parameters.setCompressionMethod(Zip4jConstants.COMP_DEFLATE);
    // parameters.setCompressionLevel(Zip4jConstants.DEFLATE_LEVEL_NORMAL);
    // parameters.setEncryptFiles(true);
    // parameters.setEncryptionMethod(Zip4jConstants.ENC_METHOD_AES);
    // parameters.setAesKeyStrength(Zip4jConstants.AES_STRENGTH_256);
    // parameters.setPassword("abc123");
    // // 压缩指定文件
    // ZipFile zipFile = new ZipFile(
    // "/home/YunXiao/YxyTmpShareDir/YxyESBagPackTmpDir/.YxYun-YxYunElectronicSchoolBagApiYw/2017-08-11/download/pack/ff8080815d30e4f3015d346b02bf0011/598c0f63d433ed0d9651c31f/zip/pack.zip");
    // zipFile.addFolder(
    // "/home/YunXiao/YxyTmpShareDir/YxyESBagPackTmpDir/.YxYun-YxYunElectronicSchoolBagApiYw/2017-08-11/download/pack/ff8080815d30e4f3015d346b02bf0011/598c0f63d433ed0d9651c31f/pack",
    // parameters);

}
